<template>
  <div>
    <!-- 头部 -->
    <!-- 插槽使用2步：
    1、使用<slot></slot>在组件内占位
    2、使用<template></template>包裹标签
    v-slot:left具有插槽
    fixd:可以让头部的div带固定定位样式(给组件内的prop传入true/false，影响到组件内的动态样式:class)
    解决：给头部导航固定定位、再给内容部分来一个内边距，给头部留一个位置，把下面的内容部分往下挤压
     -->
    <div>
      <van-nav-bar fixed>
        <template v-slot:left>
          <img class="logo" src="@/assets/logo.png" alt="">
        </template>
        <template #right>
          <!-- 坑：postcss只能翻译style里的css样式代码，而标签内的行内样式，它无法把px转换成rem，所以需要自己手动计算 18/37.5=0.48rem-->
          <van-icon name="search" size="0.48rem" color="#fff" @click="moveSearchFn" />
        </template>
      </van-nav-bar>
    </div>
    <!-- tab栏导航
   1、van-tabs：一行容器
    van-tab：每个tab栏
    v-model：关联的是激活项的下标(双向绑定)
    v-model为啥能在一个组件内用？
    因为value属性和input事件，
    能给组件里的value属性传入一个值，控制组件里面该谁高亮，
    反过来，里面点击的时候，它也能把点击的索引传出来，赋给active这个变量
    2、tab栏+内容
    3、非常重要知识点：
    每个van-tab代表一个标签导航，中间夹着的内容，对应的是下属列表内容
    4、非常重要知识点：
    每个van-tab都对应独立的自己的ArticleList(多次)
    5、细节：van-tab循环了很多导航标签，与之一一对应的内容列表不是上来就创建的，默认创建当前激活导航对应列表组件
    第一次切换到对应频道时，才会创建下属的ArticlList组件->才会执行created()方法
    第二次切换就是显示/隐藏切换
     -->
    <div class="main">
      <van-tabs v-model="channelId" sticky offset-top="1.226667rem" animated @change="channelChangeFn">
        <!-- 铺设用户频道列表数据-就是那个tab导航栏--推荐、html之类的那个 -->
        <van-tab :title="obj.name" v-for="obj in getUserChannelsList" :key="obj.id" :name="obj.id">
          <ArticleList :channelId="channelId"></ArticleList>
        </van-tab>
      </van-tabs>
      <!-- 编辑频道加号+图标 -->
      <van-icon name="plus" size="0.37333334rem" class="moreChannels" @click="plusClickFn" />

    </div>
    <!-- 频道管理弹出层 -->
    <van-popup v-model="show" get-container="body" class="channel_popup">
      <ChannelEdit :userList="getUserChannelsList" :unCheckList="unCheckChannelList" @addChannelEv="addChannelFn"
        @removeChannelEV="removeChannelFn" @closeEV="closeFn" ref="editRef" v-model="channelId">
      </ChannelEdit>
    </van-popup>
  </div>
</template>

<script>
import { getUserChannelsAPI, getAllChannelsAPI, getUpdateChannelsAPI, getDeleteChannelAPI } from '@/api'
import ArticleList from './components/ArticleList.vue'
import ChannelEdit from './ChannelEdit.vue'
// import Notify from './ui/Notify'

// 目标1：获取不同的文章新闻列表，需要传递不同的频道id
// 想法：让van-tabs的v-model关联频道id

// 目标2：点击tab标签页@change触发，重新发送请求，拿到新数据
// 问题：每次切换tab拿到的数据都是新的
// 即使你用了keep-alive也没有，它只是防止组件被销毁，而你的组件没有销毁，只是在点击切换数据
// 解决：外面现在用的是同一个数组切换数据(多个ArticleList用的是同一个数组，所以一换会影响别人)
// 文章新闻列表的数据，请求，数组，分别放到ArticleList内部(让它自己请求自己的数据)
// 外面只负责传入当前激活的频道ID
export default {
  // 缓存的组件，data里面的值不会被释放
  data() {
    return {
      channelId: 0, // tab导航-激活频道ID(默认频道ID为0，也就是页面刚打开是推荐频道高亮-对应的文章新闻列表数据)
      getUserChannelsList: [], // 获取用户频道列表数据
      // getAllArticlesList: [] // 文章新闻列表 铺设之前先定义一个数组
      show: false, // 频道弹出层控制显示/隐藏
      getAllChannelsList: [], // 所有频道的列表
      channelScrollTObj: {} // 保存每个频道的滚动位置  值构想：{推荐频道ID：对应滚动距离}
    }
  },
  async created() {
    // 获取用户的频道-就是那个tab导航栏--推荐、html之类的那个
    const res = await getUserChannelsAPI()
    console.log(res)
    this.getUserChannelsList = res.data.data.channels
    // this.channelChangeFn() // 网页打开的时候调用一下这个事件

    // 获取所有频道列表数据
    const res2 = await getAllChannelsAPI()
    console.log(res2)
    this.getAllChannelsList = res2.data.data.channels
  },
  components: {
    ArticleList,
    ChannelEdit
  },
  methods: {
    // 监测tabs切换事件，获取文章新闻列表数据
    // async channelChangeFn() {
    //   // 获取文章新闻推荐
    //   const res2 = await getAllArticlesListAPI({
    //     channel_id: this.channelId, // 先默认请求推荐频道的数据
    //     timestamp: (new Date()).getTime()
    //   })
    //   console.log(res2)
    //   this.getAllArticlesList = res2.data.data.results // 把返回的数据给这个数组，然后去标签里循环
    // }

    // tab栏切换事件
    // tab切换以后，设置滚动条的位置
    // tab切换时，这个组件内部，会把切走的容器height设置为0，滚动条因为没有高度回到了顶部，切回来的一瞬间，没有高度，滚动事件从底下上来也被触发了，所以才把数据里设置为0
    // 切回来的一瞬间，高度为0，你设置滚动位置也没用
    // 可以慢一点执行 this.$nextTick()  先让DOM更新完毕，再设置滚动位置
    channelChangeFn() {
      this.$nextTick(() => {
        document.documentElement.scrollTop = this.channelScrollTObj[this.channelId]
        document.body.scrollTop = this.channelScrollTObj[this.channelId]
      })
    },
    // +号点击方法
    plusClickFn() {
      this.show = true
    },
    // 添加我的频道
    async addChannelFn(channelObj) {
      this.getUserChannelsList.push(channelObj)
      // 问题：为什么只需要push，不需要从下面数组里移除--因为计算属性的依赖项getUserChannelsList发生改变就会被监听到，重新计算过滤

      // 推荐频道不能传递--筛选出不是推荐频道剩下的频道对象
      // const newArr = this.getUserChannelsList.filter(obj => obj.id !== 0)
      // 数组里对象字段->转换
      // newArr.forEach(obj, index)=> {
      //   //delete对象.属性 可以删除键值对
      //   delete obj.name
      //   obj.seq = index
      // })
      // const res = await getUpdateChannelsAPI({
      //   channels: newArr
      // })
      // console.log(res)
      // 上面的代码出问题：新增时，名字被删除
      // 原因：所有数组里面的对象，都是同一个内存地址，影响到ChannelEdit.vue中的对象
      // 解决：
      // const newArr = this.getUserChannelsList.filter(obj => obj.id !== 0)
      // let theNewArr=newArr.map((obj,index)=>{
      // const newObj={...obj}  浅拷贝
      //   delete obj.name
      // newObj.seq=index
      // return newObj //让我们的map方法把新对象收集起来形成一个新的数组
      // const res = await getUpdateChannelsAPI({
      //   channels: theNewArr
      // })
      // console.log(res)
      // })

      // 还要把最新的数组，发送给后台
      const res = await getUpdateChannelsAPI({
        channels: this.getUserChannelsList
      })
      console.log(res)
    },
    // 用户删除频道对象的方法
    async removeChannelFn(channelObj) {
      // channelObj.id你要删除的对象id
      // 下面做法：我要找到你要删除的是数组里哪一个对象 - 然后查找
      const index = this.getUserChannelsList.findIndex(obj => obj.id === channelObj.id)
      this.getUserChannelsList.splice(index, 1) // 从数组去掉这个元素 (劈死它)
      const res = await getDeleteChannelAPI({
        channelId: channelObj.id
      })
      console.log(res) // 删除接口返回的状态码204(Not Content 无返回内容)
      // 两种做法：
      // 第一种：把现在用户数组的数据，再覆盖式的发给后台，需要把上面更新数组的过程，封装一个函数，然后在add和remove里调用(笔记里有)
      // 第二种：只调用删除的接口
    },
    // 关闭弹出层
    closeFn() {
      this.show = false
      // 我要让内部的编辑状态回归到原来的false--第一种：在子组件中直接this.isEdit=false
      // 第二种：用ref拿到组件对象editRef，然后顺理成章拿到里面的变量isEdit
      this.$refs.editRef.isEdit = false
    },
    // 首页-右上角放大镜点击事件->跳转搜索页面
    moveSearchFn() {
      this.$router.push('/search')
    },
    // 监听网页的滚动事件
    scrollFn() {
      // 滚动的时候，把滚动位置保存到路由对象里面
      // document.documentElement.scrollTop当前html的滚动距离
      // Notify({
      // 谷歌浏览器内核和安卓手机内置浏览器的内核不是同一个
      // 获取scrollTop方式不同
      // 谷歌浏览器用的html的scrollTop
      // 有的浏览器用的body的scrollTop
      //   message: document.body.scrollTop
      // })
      this.$route.meta.scrollT = document.body.scrollTop || document.documentElement.scrollTop
      this.channelScrollTObj[this.channelId] = document.body.scrollTop
      // this.$route.meta.scrollT = document.documentElement.scrollTop
      // // 动态的变量或者表达式得用中括号[this.channelId]，具体的变量就用.点
      // // 这是在.vue中，要用this.xxx
      // // 同时保存当前频道的滚动距离 频道ID=对应滚动距离
      // this.channelScrollTObj[this.channelId] = document.documentElement.scrollTop
    }

  },
  // 计算属性
  computed: {
    unCheckChannelList() {
      // 目标：把所有的频道数组挨个对象取出，去用户已选的频道数组里去查找，如果找不到，则让filter方法收集到一个新的数组里
      // const newArr = this.getAllChannelsList.filter(bigObj => {
      //   const index = this.getUserChannelsList.findIndex(smallObj => {
      //     return smallObj.id === bigObj.id
      //   })
      //   // 如果找到了
      //   if (index > -1) {
      //     return false
      //   } else {
      //     return true
      //   }
      // })
      // return newArr

      // 优化写法-减少return出现-最好不要这样写
      return this.getAllChannelsList.filter(bigObj => this.getUserChannelsList.findIndex(smallObj => smallObj.id === bigObj.id) === -1)
    }
  },
  activated() {
    // 事件和方法是函数体后面不能加()调用
    window.addEventListener('scroll', this.scrollFn)
    // window和document，用来监听网页滚动的事件
    // html标签，用来获取scrollTop滚动的距离和滚动的位置
    // 切回来的时候，我要立刻设置滚动条的位置
    document.documentElement.scrollTop = this.$route.meta.scrollT
    document.body.scrollTop = this.$route.meta.scrollT
  },
  // 组件缓存时，失去激活生命周期方法触发
  deactivated() {
    window.removeEventListener('scroll', this.scrollFn)
  }

}
</script>

<style scoped lang="less">
.logo {
  width: 100px;
  height: 30px;
}

.main {
  padding-top: 44px;
  //底部间距在layout/index.vue给二级路由挂载点容器上给了一个padding-bottom
}

// 设置 tabs 容器的样式
/deep/ .van-tabs__wrap {
  padding-right: 30px;
  background-color: #fff;
}

// 设置小图标的样式
.moreChannels {
  position: fixed;
  top: 62px;
  right: 8px;
  z-index: 999;
}

.channel_popup {
  //如果想给百分百也行，要先给html和body设置100%
  //vw/vh是css3新出的单位，参考浏览器窗口的百分比
  width: 100vw;
  height: 100vh;
}
</style>
